#ifndef __WEEDER_H
#define __WEEDER_H

#include <gvars3/gvars3.h>
#include <vector>
#include <string>
#include "GLWindow2.h"
#include "WeederKeyFrame.h"
#include "WeederMapPoint.h"
#include "ATANCamera.h"
#include "RTree.h"
#include "SVM.h"
#include "Texture.h"
#include <opencv/cxcore.h>
#include <TooN/TooN.h>
#include "PointSet.h"
#include "RBF.h"
#include "PolygonalMesh.h"

int demo();

class Weeder
{
public:
  Weeder(bool bTraining = false);
  ~Weeder();

  bool LoadMap(const std::string sMapDirectory);
  void Detect();
  void Train();
  bool Stop();
  void TrainingLoop();
  void DetectionLoop();
  
private:
  void Reset();
  void DeleteMap();
  void ShowSelections();
  void ShowDetections();
  void ShowTexture();
  void ClearMapPointLabels();
  void ClearMapPointProbabilites();
  void ClearKeyPointTextures();
  void GUICommandHandler(std::string sCommand, std::string sParams);
  static void GUICommandCallBack(void* ptr, std::string sCommand, std::string sParams);
  
  WeederKeyFrame* CurrentKeyFrame();
  WeederKeyFrame* NextKeyFrameLoop();
  WeederKeyFrame* RemoveKeyFrame();
  void NextTextureLoop();

  void FilterMapPoints();
  void FilterKeyFrames();
  bool comp(float a, float b);
  RBF* MultiScaleRBF(PointSet *ps, const float smooth, const float error);
  void ComputeMesh();

  void EvaluateDetectionAccuracy();
  void SaveMapPoints();

  void ShowMap();
  void SetupFrustum();
  void SetupModelView(TooN::SE3<> se3WorldFromCurrent = TooN::SE3<>());
  void ShowMapDots();
  void ShowKeyFramePose(WeederKeyFrame *kf);
  void ShowMesh();
  void ShowPatches();

  bool Project(const SE3<> &se3CFromW, const Vector<3> &v3World, Vector<2> &v2Image, double &depth);

  CvScalar* ColourMap(int size);
  CvScalar* mColourMap;

  void DrawCircle(IplImage *src, CvPoint center, int radius, CvScalar colour, double alpha = 0.0, double beta = 1.0);

  TooN::Vector<3> mv3MassCenter;
  TooN::SE3<> mse3ViewerFromWorld;

  GLWindow2 *mpGLWindow;
  bool mbDone;
  bool mbTraining;

  std::vector<std::string> mvsClassNames;
  std::vector<struct SVM::svm_model*> msvmClassDetector;
  std::vector<struct SVM::svm_approx_model*> msvmApproxClassDetector;

  CvSize mImSize;
  ATANCamera *mCamera;
  Texture<WeederMapPoint*> *mTexGenerator;
  IplImage *mBackground;
  IplImage *mPatchMask;
  double *mTextureShift;
  double *mTextureScale;
  unsigned int mFeatureDim;

  std::string msMapDirectory;
  
  int mnCurrentTexture;
  std::vector<WeederKeyFrame*>::iterator mitvKeyFrames;
  std::vector<WeederKeyFrame*> mvKeyFrames;
  std::vector<WeederMapPoint*> mvMapPoints;
  std::vector<WeederMapPoint*> mvFilteredMapPoints;

  PolygonalMesh mesh;

  int mnCameraWidth, mnCameraHeight;
  GVars3::gvar3<int> mgvnGreylevels;
  GVars3::gvar3<int> mgvnSparseSampleSpacing;
  GVars3::gvar3<int> mgvnDenseSampleSpacing;
  GVars3::gvar3<int> mgvnApproxSamplesSVM;
  GVars3::gvar3<double> mgvdDbscanEps;
  GVars3::gvar3<int> mgvnDbscanMinObs;
  GVars3::gvar3<int> mgvnMapPointMinObs;
  GVars3::gvar3<int> mgvnDbscanClusterMinObs;
  GVars3::gvar3<double> mgvdMaxScaleDepth;
  GVars3::gvar3<int> mgvnUseApproxSVM;
  GVars3::gvar3<int> mgvnCameraWidth;
  GVars3::gvar3<int> mgvnCameraHeight;
  GVars3::gvar3<int> mgvnCurrentClass;
  GVars3::gvar3<std::string> mgvsKeyFramesFilename;
  GVars3::gvar3<std::string> mgvsMapPointsFilename;
  GVars3::gvar3<std::string> mgvsTextureScaleFilename;
};

inline bool IsLabelled(const KeyPoint<WeederMapPoint*> &kpt)
{
  return(kpt.data->nClassLabel >= 0);
}

#endif
